﻿// 示例代码 4-3
// 线程安全的shared_ptr
#include <iostream>
#include <atomic>
#include <mutex>
#include <thread>
#include <cassert>
#include <functional>
using namespace std;

namespace yyp
{
	template <class T>
	class shared_ptr
	{
	public:
		explicit shared_ptr(T* ptr = nullptr)
			: _ptr(ptr)
			, _pcount(new atomic<int>(1))
		{}

		template <class U, class D>
		shared_ptr(U* ptr, D del)
			: _ptr(ptr)
			, _pcount(new atomic<int>(1))
			, _del(del)
		{}

		shared_ptr(const shared_ptr& sp)
		{
			std::unique_lock<std::mutex> lk(_mtx);

			// 避免sp被并发修改
			_ptr = sp._ptr;
			_pcount = sp._pcount;
			_del = sp._del;

			if (_pcount)
				++(*_pcount);
		}

		shared_ptr(shared_ptr&& sp)
		{
			std::unique_lock<std::mutex> lk(_mtx);

			_ptr = sp._ptr;
			_pcount = sp._pcount;
			_del = sp._del;

			sp._ptr = nullptr;
			sp._pcount = nullptr;
			sp._del = nullptr;
		}

		shared_ptr& operator=(const shared_ptr& sp)
		{
			std::unique_lock<std::mutex> lk(_mtx);

			//if (this != &sp)
			if (_ptr != sp._ptr)
			{
				release();

				_ptr = sp._ptr;
				_pcount = sp._pcount;
				++(*_pcount);
				_del = sp._del;
			}

			return *this;
		}

		shared_ptr& operator=(shared_ptr&& sp)
		{
			std::unique_lock<std::mutex> lk(_mtx);

			if (_ptr != sp._ptr)
			{
				release();

				_ptr = sp._ptr;
				_pcount = sp._pcount;
				++(*_pcount);
				_del = move(sp._del); // 移动删除器（function支持移动，更高效）
			}

			return *this;
		}

		void release()
		{
			if (_pcount && 0 == --(*_pcount))
			{
				// 最后⼀个管理资源的对象析构时，释放其管理的资源
				_del(_ptr);
				delete _pcount;
				_ptr = nullptr;
				_pcount = nullptr;
			}
		}

		T& operator*() const
		{
			if (!_ptr)
				assert(false);

			return *_ptr;
		}

		T* operator->() const
		{
			if (!_ptr)
				assert(false);

			return _ptr;
		}

		int use_count() const
		{
			return _pcount ? _pcount->load() : 0;
		}

		T* get() const
		{
			return _ptr;
		}

		~shared_ptr()
		{
			// 备份当前计数，防止读取打印的过程中，被其它线程修改数据
			int cur_count = _pcount ? _pcount->load() : 0;
			bool will_release = (_pcount && 1 == cur_count);

			unique_lock<mutex> lk(_mtx);
			cout << "shared_ptr delete: ";
			if (!_ptr)
			{
				cout << "空对象";
			}
			else
			{
				cout << "引用计数 " << cur_count;
				if (will_release)
					cout << " ，释放管理的资源 " << _ptr;
			}
			cout << endl;

			release();
		}

	private:
		T* _ptr;
		atomic<int>* _pcount;
		static mutex _mtx;

		function<void(T*)> _del = [](T* ptr) {
			delete ptr;
			ptr = nullptr;
		};
	};
	template <class T>
	mutex shared_ptr<T>::_mtx;
}

void Test7()
{
	struct A
	{
		int _a = 0;
		int _b = 0;

		~A()
		{
			cout << "~A" << endl;
		}
	};

	mutex Mutex;
	const size_t N = 3;
	yyp::shared_ptr<A> sp(new A());

	auto f = [&]
	{
		for (size_t i = 0; i < N; ++i)
		{
			yyp::shared_ptr<A> copy(sp);

			{
				unique_lock<mutex> lk(Mutex);
				++copy->_a;
				++copy->_b;
			}
		}
	};

	thread t1(f);
	thread t2(f);

	t1.join();
	t2.join();

	cout << "\n************" << endl;
	cout << sp.use_count() << endl;
	cout << sp->_a << " " << sp->_b << endl;
	cout << "************" << endl << endl;
}

int main()
{
	Test7();

	return 0;
}
